<?php
/**
 * ---------------------------------------------------------------------
 * GLPI - Gestionnaire Libre de Parc Informatique
 * Copyright (C) 2015-2018 Teclib' and contributors.
 *
 * http://glpi-project.org
 *
 * based on GLPI - Gestionnaire Libre de Parc Informatique
 * Copyright (C) 2003-2014 by the INDEPNET Development Team.
 *
 * ---------------------------------------------------------------------
 *
 * LICENSE
 *
 * This file is part of GLPI.
 *
 * GLPI is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * GLPI is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GLPI. If not, see <http://www.gnu.org/licenses/>.
 * ---------------------------------------------------------------------
 */

if (!defined('GLPI_ROOT')) {
   die("Sorry. You can't access this file directly");
}

/**
 * LevelAgreement base Class for OLA & SLA
 * @since 9.2
**/

abstract class LevelAgreement extends CommonDBChild {
   // From CommonDBTM
   var $dohistory          = true;
   static $rightname       = 'slm';

   // From CommonDBChild
   static public $itemtype = 'SLM';
   static public $items_id = 'slms_id';


   /**
    * Display a specific OLA or SLA warning.
    * Called into the above showForm() function
    *
    * @return void
    */
   abstract function showFormWarning();

   /**
    * Return the text needed for a confirmation of adding level agreement to a ticket
    *
    * @return array of strings
    */
   abstract function getAddConfirmation();

   /**
    * Get table fields
    *
    * @param integer $subtype of OLA/SLA, can be SLM::TTO or SLM::TTR
    *
    * @return array of 'date' and 'sla' field names
    */
   static function getFieldNames($subtype) {

      $dateField = null;
      $laField  = null;

      switch ($subtype) {
         case SLM::TTO:
            $dateField = static::$prefixticket.'time_to_own';
            $laField   = static::$prefix.'s_id_tto';
            break;

         case SLM::TTR:
            $dateField = static::$prefixticket.'time_to_resolve';
            $laField   = static::$prefix.'s_id_ttr';
            break;
      }
      return [$dateField, $laField];
   }

   function defineTabs($options = []) {

      $ong = [];
      $this->addDefaultFormTab($ong);
      $this->addStandardTab(static::$levelclass, $ong, $options);
      $this->addStandardTab('Rule', $ong, $options);
      $this->addStandardTab('Ticket', $ong, $options);

      return $ong;
   }

   /**
    * Define calendar of the ticket using the SLA/OLA when using this calendar as sla/ola-s calendar
    *
    * @param integer $calendars_id calendars_id of the ticket
   **/
   function setTicketCalendar($calendars_id) {

      if ($this->fields['calendars_id'] == -1) {
         $this->fields['calendars_id'] = $calendars_id;
      }
   }

   function post_getFromDB() {
      // get calendar from slm
      $slm = new SLM;
      if ($slm->getFromDB($this->fields['slms_id'])) {
         $this->fields['calendars_id'] = $slm->fields['calendars_id'];
      }
   }

   function post_getEmpty() {
      $this->fields['number_time'] = 4;
      $this->fields['definition_time'] = 'hour';
   }

   /**
    * Print the form
    *
    * @param $ID        integer  ID of the item
    * @param $options   array    of possible options:
    *     - target filename : where to go when done.
    *     - withtemplate boolean : template or basic item
    *
    *@return boolean item found
   **/
   function showForm($ID, $options = []) {
      $rowspan = 3;
      if ($ID > 0) {
         $rowspan = 5;
      }

      // Get SLM object
      $slm = new SLM();
      if (isset($options['parent'])) {
         $slm = $options['parent'];
      } else {
         $slm->getFromDB($this->fields['slms_id']);
      }

      if ($ID > 0) {
         $this->check($ID, READ);
      } else {
         // Create item
         $options[static::$items_id] = $slm->getField('id');

         //force itemtype of parent
         static::$itemtype = get_class($slm);

         $this->check(-1, CREATE, $options);
      }

      $this->showFormHeader($options);
      echo "<tr class='tab_bg_1'>";
      echo "<td>".__('Name')."</td>";
      echo "<td>";
      Html::autocompletionTextField($this, "name", ['value' => $this->fields["name"]]);
      echo "<td rowspan='".$rowspan."'>".__('Comments')."</td>";
      echo "<td rowspan='".$rowspan."'>
            <textarea cols='45' rows='8' name='comment' >".$this->fields["comment"]."</textarea>";
      echo "</td></tr>";

      echo "<tr class='tab_bg_1'>";
      echo "<td>".__('SLM')."</td>";
      echo "<td>";
      echo $slm->getLink();
      echo "<input type='hidden' name='slms_id' value='".$this->fields['slms_id']."'>";
      echo "</td></tr>";

      if ($ID > 0) {
         echo "<tr class='tab_bg_1'>";
         echo "<td>".__('Last update')."</td>";
         echo "<td>".($this->fields["date_mod"] ? Html::convDateTime($this->fields["date_mod"])
                                                : __('Never'));
         echo "</td></tr>";
      }

      echo "<tr class='tab_bg_1'><td>".__('Type')."</td>";
      echo "<td>";
      self::getTypeDropdown(['value' => $this->fields["type"]]);
      echo "</td>";
      echo "</tr>";

      echo "<tr class='tab_bg_1'><td>".__('Maximum time')."</td>";
      echo "<td>";
      Dropdown::showNumber("number_time", ['value' => $this->fields["number_time"],
                                           'min'   => 0]);
      $possible_values = ['minute' => _n('Minute', 'Minutes', Session::getPluralNumber()),
                          'hour'   => _n('Hour', 'Hours', Session::getPluralNumber()),
                          'day'    => _n('Day', 'Days', Session::getPluralNumber())];
      $rand = Dropdown::showFromArray('definition_time', $possible_values,
                                      ['value'     => $this->fields["definition_time"],
                                       'on_change' => 'appearhideendofworking()']);
      echo "\n<script type='text/javascript' >\n";
      echo "function appearhideendofworking() {\n";
      echo "if ($('#dropdown_definition_time$rand option:selected').val() == 'day') {
               $('#title_endworkingday').show();
               $('#dropdown_endworkingday').show();
            } else {
               $('#title_endworkingday').hide();
               $('#dropdown_endworkingday').hide();
            }";
      echo "}\n";
      echo "appearhideendofworking();\n";
      echo "</script>\n";

      echo "</td></tr>";

      echo "<tr class='tab_bg_1'>";
      echo "<td><div id='title_endworkingday'>".__('End of working day')."</div></td>";
      echo "<td><div id='dropdown_endworkingday'>";
      Dropdown::showYesNo("end_of_working_day", $this->fields["end_of_working_day"]);
      echo "</div></td>";

      echo "<td colspan='2'>";
      $this->showFormWarning();
      echo "</td>";
      echo "</tr>";

      $this->showFormButtons($options);

      return true;
   }


   /**
    * Show for ticket
    *
    * @param  Ticket         $ticket Ticket item
    * @param  integer        $type
    * @param  ITILTemplate $tt ticket template object
    * @param  bool           $canupdate update right
    */
   function showForTicket(Ticket $ticket, $type, $tt, $canupdate) {
      list($dateField, $laField) = static::getFieldNames($type);
      $rand = mt_rand();
      $pre  = static::$prefix;
      echo "<table width='100%'>";
      echo "<tr class='tab_bg_1'>";

      if (!isset($ticket->fields[$dateField]) || $ticket->fields[$dateField] == 'NULL') {
         $ticket->fields[$dateField]='';
      }

      if ($ticket->fields['id']) {
         if ($this->getDataForTicket($ticket->fields['id'], $type)) {
            echo "<td style='width: 105px'>";
            echo $tt->getBeginHiddenFieldValue($dateField);
            echo Html::convDateTime($ticket->fields[$dateField]);
            echo $tt->getEndHiddenFieldValue($dateField, $ticket);
            echo "</td>";
            echo "<td>";
            echo $tt->getBeginHiddenFieldText($laField);
            echo "<i class='far fa-clock slt'></i>";
            echo Dropdown::getDropdownName(static::getTable(),
                                           $ticket->fields[$laField])."&nbsp;";
            echo Html::hidden($laField, ['value' => $ticket->fields[$laField]]);
            $comment = isset($this->fields['comment']) ? $this->fields['comment'] : '';
            $level      = new static::$levelclass();
            $nextaction = new static::$levelticketclass();
            if ($nextaction->getFromDBForTicket($ticket->fields["id"], $type)) {
               $comment .= '<br/><span class="b spaced">'.
                             sprintf(__('Next escalation: %s'),
                                     Html::convDateTime($nextaction->fields['date'])).
                           '</span><br>';
               if ($level->getFromDB($nextaction->fields[$pre.'levels_id'])) {
                  $comment .= '<span class="b spaced">'.
                                sprintf(__('%1$s: %2$s'), __('Escalation level'),
                                        $level->getName()).
                              '</span>';
               }
            }

            $options = [];
            if (Session::haveRight('slm', READ)) {
               $options['link'] = $this->getLinkURL();
            }
            Html::showToolTip($comment, $options);
            if ($canupdate) {
               $delete_field = strtolower(get_called_class())."_delete";
               $fields = [$delete_field       => $delete_field,
                          'id'                => $ticket->getID(),
                          'type'              => $type,
                          '_glpi_csrf_token'  => Session::getNewCSRFToken(),
                          '_glpi_simple_form' => 1];
               $ticket_url = $ticket->getFormURL();
               echo Html::scriptBlock("
               function delete_date$type$rand(e) {
                  e.preventDefault();

                  if (nativeConfirm('".addslashes(__('Also delete date?'))."')) {
                     submitGetLink('$ticket_url',
                                   ".json_encode(array_merge($fields, ['delete_date' => 1])).");
                  } else {
                     submitGetLink('$ticket_url',
                                   ".json_encode(array_merge($fields, ['delete_date' => 0])).");
                  }
               }");
               echo "<a class='fa fa-times-circle pointer'
                        onclick='delete_date$type$rand(event)'
                        title='"._sx('button', 'Delete permanently')."'>";
               echo "<span class='sr-only'>"._x('button', 'Delete permanently')."</span>";
               echo "</a>";
            }
            echo $tt->getEndHiddenFieldText($laField);
            echo "</td>";

         } else {
            echo "<td width='200px'>";
            echo $tt->getBeginHiddenFieldValue($dateField);
            echo "<span class='assign_la'>";
            if ($canupdate) {
               Html::showDateTimeField($dateField, ['value'      => $ticket->fields[$dateField],
                                                    'timestep'   => 1,
                                                    'maybeempty' => true]);
            } else {
               echo Html::convDateTime($ticket->fields[$dateField]);
            }
            echo "</span>";
            echo $tt->getEndHiddenFieldValue($dateField, $ticket);
            $data     = $this->find(
               ['type' => $type] + getEntitiesRestrictCriteria('', '', $ticket->fields['entities_id'], true)
            );
            if ($canupdate
                && !empty($data)) {
               echo $tt->getBeginHiddenFieldText($laField);
               echo "<span id='la_action$type$rand' class='assign_la'>";
               echo "<a ".Html::addConfirmationOnAction($this->getAddConfirmation(),
                        "cleanhide('la_action$type$rand');cleandisplay('la_choice$type$rand');").
                    " class='pointer' title='".static::getTypeName()."'>
                    <i class='far fa-clock slt'></i></a>";
               echo "</span>";
               echo "<span id='la_choice$type$rand' style='display:none' class='assign_la'>";
               echo "<i class='far fa-clock slt'></i>";
               echo "<span class='b'>".static::getTypeName()."</span>&nbsp;";
               static::dropdown([
                  'name'      => $laField,
                  'entity'    => $ticket->fields["entities_id"],
                  'condition' => ['type' => $type]
               ]);
               echo "</span>";
               echo $tt->getEndHiddenFieldText($laField);
            }
            echo "</td>";
         }

      } else { // New Ticket
         echo "<td>";
         echo $tt->getBeginHiddenFieldValue($dateField);
         Html::showDateTimeField($dateField, ['value'      => $ticket->fields[$dateField],
                                              'timestep'   => 1,
                                              'maybeempty' => false,
                                              'canedit'    => $canupdate,
                                              'required'   => $tt->isMandatoryField($dateField)]);
         echo $tt->getEndHiddenFieldValue($dateField, $ticket);
         echo "</td>";
         $data     = $this->find(
            ['type' => $type] + getEntitiesRestrictCriteria('', '', $ticket->fields['entities_id'], true)
         );
         if ($canupdate
             && !empty($data)) {
            echo $tt->getBeginHiddenFieldText($laField);
            if (!$tt->isHiddenField($laField) || $tt->isPredefinedField($laField)) {
               echo "<th>".sprintf(__('%1$s%2$s'),
                                   static::getTypeName(),
                                   $tt->getMandatoryMark($laField))."</th>";
            }
            echo $tt->getEndHiddenFieldText($laField);
            echo "<td class='nopadding'>".$tt->getBeginHiddenFieldValue($laField);
            static::dropdown([
               'name'      => $laField,
               'entity'    => $ticket->fields["entities_id"],
               'value'     => isset($ticket->fields[$laField]) ? $ticket->fields[$laField] : 0,
               'condition' => ['type' => $type]
            ]);
            echo $tt->getEndHiddenFieldValue($laField, $ticket);
            echo "</td>";
         }
      }

      echo "</tr>";
      echo "</table>";
   }


   /**
    * Print the HTML for a SLM
    *
    * @param SLM $slm Slm item
    */
   static function showForSLM(SLM $slm) {
      global $CFG_GLPI;

      if (!$slm->can($slm->fields['id'], READ)) {
         return false;
      }

      $instID   = $slm->fields['id'];
      $la       = new static();
      $calendar = new Calendar();
      $rand     = mt_rand();
      $canedit  = ($slm->canEdit($instID)
                   && Session::getCurrentInterface() == "central");

      if ($canedit) {
         echo "<div id='showLa$instID$rand'></div>\n";

         echo "<script type='text/javascript' >";
         echo "function viewAddLa$instID$rand() {";
         $params = ['type'                     => $la->getType(),
                    'parenttype'               => $slm->getType(),
                    $slm->getForeignKeyField() => $instID,
                    'id'                       => -1];
         Ajax::updateItemJsCode("showLa$instID$rand",
                                $CFG_GLPI["root_doc"]."/ajax/viewsubitem.php", $params);
         echo "}";
         echo "</script>";
         echo "<div class='center firstbloc'>".
               "<a class='vsubmit' href='javascript:viewAddLa$instID$rand();'>";
         echo __('Add a new item')."</a></div>\n";
      }

      // list
      $laList = $la->find(['slms_id' => $instID]);
      Session::initNavigateListItems(__CLASS__,
                                     sprintf(__('%1$s = %2$s'),
                                             $slm::getTypeName(1),
                                             $slm->getName()));
      echo "<div class='spaced'>";
      if (count($laList)) {
         if ($canedit) {
            Html::openMassiveActionsForm('mass'.__CLASS__.$rand);
            $massiveactionparams = ['container' => 'mass'.__CLASS__.$rand];
            Html::showMassiveActions($massiveactionparams);
         }

         echo "<table class='tab_cadre_fixehov'>";
         $header_begin  = "<tr>";
         $header_top    = '';
         $header_bottom = '';
         $header_end    = '';
         if ($canedit) {
            $header_top .= "<th width='10'>".Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand);
            $header_top .= "</th>";
            $header_bottom .= "<th width='10'>".Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand);
            $header_bottom .= "</th>";
         }
         $header_end .= "<th>".__('Name')."</th>";
         $header_end .= "<th>".__('Type')."</th>";
         $header_end .= "<th>".__('Maximum time')."</th>";
         $header_end .= "<th>".__('Calendar')."</th>";

         echo $header_begin.$header_top.$header_end;
         foreach ($laList as $val) {
            $edit = ($canedit ? "style='cursor:pointer' onClick=\"viewEditLa".
                        $instID.$val["id"]."$rand();\""
                        : '');
            echo "<script type='text/javascript' >";
            echo "function viewEditLa".$instID.$val["id"]."$rand() {";
            $params = ['type'                     => $la->getType(),
                       'parenttype'               => $slm->getType(),
                       $slm->getForeignKeyField() => $instID,
                       'id'                       => $val["id"]];
            Ajax::updateItemJsCode("showLa$instID$rand",
                                   $CFG_GLPI["root_doc"]."/ajax/viewsubitem.php", $params);
            echo "};";
            echo "</script>\n";

            echo "<tr class='tab_bg_1'>";
            echo "<td width='10' $edit>";
            if ($canedit) {
               Html::showMassiveActionCheckBox($la->getType(), $val['id']);
            }
            echo "</td>";
            $la->getFromDB($val['id']);
            echo "<td $edit>".$la->getLink()."</td>";
            echo "<td $edit>".$la->getSpecificValueToDisplay('type', $la->fields['type'])."</td>";
            echo "<td $edit>";
            echo $la->getSpecificValueToDisplay('number_time',
                  ['number_time'     => $la->fields['number_time'],
                   'definition_time' => $la->fields['definition_time']]);
            echo "</td>";
            if (!$slm->fields['calendars_id']) {
               $link =  __('24/7');
            } else if ($slm->fields['calendars_id'] == -1) {
               $link = __('Calendar of the ticket');
            } else if ($calendar->getFromDB($slm->fields['calendars_id'])) {
               $link = $calendar->getLink();
            }
            echo "<td $edit>".$link."</td>";
            echo "</tr>";
         }
         echo $header_begin.$header_bottom.$header_end;
         echo "</table>";

         if ($canedit) {
            $massiveactionparams['ontop'] = false;
            Html::showMassiveActions($massiveactionparams);
            Html::closeForm();
         }
      } else {
         echo __('No item to display');
      }
      echo "</div>";
   }

   /**
    * Display a list of rule for the current sla/ola
    * @return void
    */
   function showRulesList() {
      global $DB;

      $fk      = static::getFieldNames($this->fields['type'])[1];
      $rule    = new RuleTicket;
      $rand    = mt_rand();
      $canedit = self::canUpdate();

      $rules_id_list = iterator_to_array($DB->request([
         'SELECT'          => 'rules_id',
         'DISTINCT'        => true,
         'FROM'            => 'glpi_ruleactions',
         'WHERE'           => [
            'field' => $fk,
            'value' => $this->getID()]]));
      $nb = count($rules_id_list);

      echo "<div class='spaced'>";
      if (!$nb) {
         echo "<table class='tab_cadre_fixehov'>";
         echo "<tr><th>" . __('No item found') . "</th>";
         echo "</tr>\n";
         echo "</table>\n";

      } else {
         if ($canedit) {
            Html::openMassiveActionsForm('massRuleTicket'.$rand);
            $massiveactionparams
               = ['num_displayed'    => min($_SESSION['glpilist_limit'], $nb),
                  'specific_actions' => ['update' => _x('button', 'Update'),
                                         'purge'  => _x('button', 'Delete permanently')]];
            Html::showMassiveActions($massiveactionparams);
         }
         echo "<table class='tab_cadre_fixehov'>";
         $header_begin  = "<tr>";
         $header_top    = '';
         $header_bottom = '';
         $header_end    = '';
         if ($canedit) {
            $header_begin  .= "<th width='10'>";
            $header_top    .= Html::getCheckAllAsCheckbox('massRuleTicket'.$rand);
            $header_bottom .= Html::getCheckAllAsCheckbox('massRuleTicket'.$rand);
            $header_end    .= "</th>";
         }
         $header_end .= "<th>" . RuleTicket::getTypeName($nb) . "</th>";
         $header_end .= "<th>" . __('Active') . "</th>";
         $header_end .= "<th>" . __('Description') . "</th>";
         $header_end .= "</tr>\n";
         echo $header_begin.$header_top.$header_end;

         Session::initNavigateListItems(get_class($this),
                                        sprintf(__('%1$s = %2$s'),
                                                $rule->getTypeName(1), $rule->getName()));

         foreach ($rules_id_list as $data) {
            $rule->getFromDB($data['rules_id']);
            Session::addToNavigateListItems(get_class($this), $rule->fields["id"]);
            echo "<tr class='tab_bg_1'>";

            if ($canedit) {
               echo "<td width='10'>";
               Html::showMassiveActionCheckBox("RuleTicket", $rule->fields["id"]);
               echo "</td>";
               $ruleclassname = get_class($rule);
               echo "<td><a href='".$ruleclassname::getFormURLWithID($rule->fields["id"])
                       . "&amp;onglet=1'>" .$rule->fields["name"] ."</a></td>";

            } else {
               echo "<td>" . $rule->fields["name"] . "</td>";
            }

            echo "<td>" . Dropdown::getYesNo($rule->fields["is_active"]) . "</td>";
            echo "<td>" . $rule->fields["description"] . "</td>";
            echo "</tr>\n";
         }
         echo $header_begin.$header_bottom.$header_end;
         echo "</table>\n";

         if ($canedit) {
            $massiveactionparams['ontop'] = false;
            Html::showMassiveActions($massiveactionparams);
            Html::closeForm();
         }
      }
      echo "</div>";
   }

   function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {

      if (!$withtemplate) {
         $nb = 0;
         switch ($item->getType()) {
            case 'SLM' :
               if ($_SESSION['glpishow_count_on_tabs']) {
                  $nb = countElementsInTable(self::getTable(),
                                             ['slms_id' => $item->getField('id')]);
               }
               return self::createTabEntry(static::getTypeName($nb), $nb);
         }
      }
      return '';
   }


   static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) {

      switch ($item->getType()) {
         case 'SLM' :
            self::showForSLM($item);
            break;
      }
      return true;
   }


   /**
    * Get data by type and ticket
    *
    * @param $tickets_id
    * @param $type
    */
   function getDataForTicket($tickets_id, $type) {
      global $DB;

      list($dateField, $field) = static::getFieldNames($type);

      $iterator = $DB->request([
         'SELECT'       => [static::getTable() . '.id'],
         'FROM'         => static::getTable(),
         'INNER JOIN'   => [
            'glpi_tickets' => [
               'FKEY'   => [
                  static::getTable()   => 'id',
                  'glpi_tickets'       => $field
               ]
            ]
         ],
         'WHERE'        => ['glpi_tickets.id' => $tickets_id],
         'LIMIT'        => 1
      ]);

      if (count($iterator)) {
         return $this->getFromIter($iterator);
      }
      return false;
   }


   function rawSearchOptions() {
      $tab = [];

      $tab[] = [
         'id'                 => 'common',
         'name'               => __('Characteristics')
      ];

      $tab[] = [
         'id'                 => '1',
         'table'              => $this->getTable(),
         'field'              => 'name',
         'name'               => __('Name'),
         'datatype'           => 'itemlink',
         'massiveaction'      => false
      ];

      $tab[] = [
         'id'                 => '2',
         'table'              => $this->getTable(),
         'field'              => 'id',
         'name'               => __('ID'),
         'massiveaction'      => false,
         'datatype'           => 'number'
      ];

      $tab[] = [
         'id'                 => '5',
         'table'              => $this->getTable(),
         'field'              => 'number_time',
         'name'               => __('Time'),
         'datatype'           => 'specific',
         'massiveaction'      => false,
         'nosearch'           => true,
         'additionalfields'   => ['definition_time']
      ];

      $tab[] = [
         'id'                 => '6',
         'table'              => $this->getTable(),
         'field'              => 'end_of_working_day',
         'name'               => __('End of working day'),
         'datatype'           => 'bool',
         'massiveaction'      => false
      ];

      $tab[] = [
         'id'                 => '7',
         'table'              => $this->getTable(),
         'field'              => 'type',
         'name'               => __('Type'),
         'datatype'           => 'specific'
      ];

      $tab[] = [
         'id'                 => '8',
         'table'              => 'glpi_slms',
         'field'              => 'name',
         'name'               => __('SLM'),
         'datatype'           => 'dropdown'
      ];

      $tab[] = [
         'id'                 => '16',
         'table'              => $this->getTable(),
         'field'              => 'comment',
         'name'               => __('Comments'),
         'datatype'           => 'text'
      ];

      return $tab;
   }


   /**
    * @param $field
    * @param $values
    * @param $options   array
   **/
   static function getSpecificValueToDisplay($field, $values, array $options = []) {

      if (!is_array($values)) {
         $values = [$field => $values];
      }
      switch ($field) {
         case 'number_time' :
            switch ($values['definition_time']) {
               case 'minute' :
                  return sprintf(_n('%d minute', '%d minutes', $values[$field]), $values[$field]);

               case 'hour' :
                  return sprintf(_n('%d hour', '%d hours', $values[$field]), $values[$field]);

               case 'day' :
                  return sprintf(_n('%d day', '%d days', $values[$field]), $values[$field]);
            }
            break;

         case 'type' :
            return self::getOneTypeName($values[$field]);
      }
      return parent::getSpecificValueToDisplay($field, $values, $options);
   }


   /**
    * @param $field
    * @param $name            (default '')
    * @param $values          (default '')
    * @param $options   array
    *
    * @return string
   **/
   static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = []) {

      if (!is_array($values)) {
         $values = [$field => $values];
      }
      $options['display'] = false;
      switch ($field) {
         case 'type':
            $options['value'] = $values[$field];
            return self::getTypeDropdown($options);
      }
      return parent::getSpecificValueToSelect($field, $name, $values, $options);
   }


   /**
    * Get computed resolution time
    *
    * @return integer resolution time (default 0)
   **/
   function getTime() {

      if (isset($this->fields['id'])) {
         if ($this->fields['definition_time'] == "minute") {
            return $this->fields['number_time'] * MINUTE_TIMESTAMP;
         }
         if ($this->fields['definition_time'] == "hour") {
            return $this->fields['number_time'] * HOUR_TIMESTAMP;
         }
         if ($this->fields['definition_time'] == "day") {
            return $this->fields['number_time'] * DAY_TIMESTAMP;
         }
      }
      return 0;
   }


   /**
    * Get active time between to date time for the active calendar
    *
    * @param datetime $start begin
    * @param datetime $end end
    *
    * @return integer timestamp of delay
    **/
   function getActiveTimeBetween($start, $end) {

      if ($end < $start) {
         return 0;
      }

      if (isset($this->fields['id'])) {
         $cal          = new Calendar();
         $work_in_days = ($this->fields['definition_time'] == 'day');

         // Based on a calendar
         if ($this->fields['calendars_id'] > 0) {
            if ($cal->getFromDB($this->fields['calendars_id'])) {
               return $cal->getActiveTimeBetween($start, $end, $work_in_days);
            }

         } else { // No calendar
            $timestart = strtotime($start);
            $timeend   = strtotime($end);
            return ($timeend-$timestart);
         }
      }
      return 0;
   }


   /**
    * Get date for current agreement
    *
    * @param $start_date         datetime start date
    * @param $additional_delay   integer  additional delay to add or substract (for waiting time)
    *                                     (default 0)
    *
    * @return due date time (NULL if sla/ola not exists)
   **/
   function computeDate($start_date, $additional_delay = 0) {

      if (isset($this->fields['id'])) {
         $delay = $this->getTime();
         // Based on a calendar
         if ($this->fields['calendars_id'] > 0) {
            $cal          = new Calendar();
            $work_in_days = ($this->fields['definition_time'] == 'day');

            if ($cal->getFromDB($this->fields['calendars_id'])) {
               return $cal->computeEndDate($start_date, $delay,
                                           $additional_delay, $work_in_days,
                                           $this->fields['end_of_working_day']);
            }
         }

         // No calendar defined or invalid calendar
         if ($this->fields['number_time'] >= 0) {
            $starttime = strtotime($start_date);
            $endtime   = $starttime + $delay + $additional_delay;
            return date('Y-m-d H:i:s', $endtime);
         }
      }

      return null;
   }


   /**
    * Get execution date of a level
    *
    * @param $start_date         datetime    start date
    * @param $levels_id          integer     sla/ola level id
    * @param $additional_delay   integer     additional delay to add or substract (for waiting time)
    *                                        (default 0)
    *
    * @return execution date time (NULL if ola/sla not exists)
   **/
   function computeExecutionDate($start_date, $levels_id, $additional_delay = 0) {

      if (isset($this->fields['id'])) {
         $level = new static::$levelclass();
         $fk = getForeignKeyFieldForItemType(get_called_class());

         if ($level->getFromDB($levels_id)) { // level exists
            if ($level->fields[$fk] == $this->fields['id']) { // correct level
               $work_in_days = ($this->fields['definition_time'] == 'day');
               $delay        = $this->getTime();

               // Based on a calendar
               if ($this->fields['calendars_id'] > 0) {
                  $cal = new Calendar();
                  if ($cal->getFromDB($this->fields['calendars_id'])) {
                     return $cal->computeEndDate($start_date, $delay,
                                                 $level->fields['execution_time'] + $additional_delay,
                                                 $work_in_days);
                  }
               }
               // No calendar defined or invalid calendar
               $delay    += $additional_delay+$level->fields['execution_time'];
               $starttime = strtotime($start_date);
               $endtime   = $starttime+$delay;
               return date('Y-m-d H:i:s', $endtime);
            }
         }
      }
      return null;
   }


   /**
    * Get types
    *
    * @return array array of types
    **/
   static function getTypes() {
      return [SLM::TTO => __('Time to own'),
              SLM::TTR => __('Time to resolve')];
   }


   /**
    * Get types name
    *
    * @param type $type
    * @return string name
    **/
   static function getOneTypeName($type) {

      $types = self::getTypes();
      $name  = null;
      if (isset($types[$type])) {
         $name = $types[$type];
      }
      return $name;
   }


   /**
    * Get SLA types dropdown
    *
    * @param array $options
    *
    * @return string
    */
   static function getTypeDropdown($options) {

      $params = ['name'  => 'type'];

      foreach ($options as $key => $val) {
         $params[$key] = $val;
      }

      return Dropdown::showFromArray($params['name'], self::getTypes(), $options);
   }


   function prepareInputForAdd($input) {

      if ($input['definition_time'] != 'day') {
         $input['end_of_working_day'] = 0;
      }
      return $input;
   }


   function prepareInputForUpdate($input) {

      if (isset($input['definition_time']) && $input['definition_time'] != 'day') {
         $input['end_of_working_day'] = 0;
      }
      return $input;
   }


   /**
    * Add a level to do for a ticket
    *
    * @param Ticket  $ticket Ticket object
    * @param integer $levels_id SlaLevel or OlaLevel ID
    *
    * @return void
    **/
   function addLevelToDo(Ticket $ticket, $levels_id = 0) {

      $pre = static::$prefix;

      if (!$levels_id && isset($ticket->fields[$pre.'levels_id_ttr'])) {
         $levels_id = $ticket->fields[$pre."levels_id_ttr"];
      }

      if ($levels_id) {
         $toadd = [];
         $date = $this->computeExecutionDate($ticket->fields['date'], $levels_id,
                                             $ticket->fields[$pre.'_waiting_duration']);
         if ($date != null) {
            $toadd['date']           = $date;
            $toadd[$pre.'levels_id'] = $levels_id;
            $toadd['tickets_id']     = $ticket->fields["id"];
            $levelticket             = new static::$levelticketclass();
            $levelticket->add($toadd);
         }
      }
   }


   /**
    * remove a level to do for a ticket
    *
    * @param $ticket Ticket object
    *
    * @return void
   **/
   static function deleteLevelsToDo(Ticket $ticket) {
      global $DB;

      $ticketfield = static::$prefix."levels_id_ttr";

      if ($ticket->fields[$ticketfield] > 0) {
         $levelticket = new static::$levelticketclass();
         $iterator = $DB->request([
            'SELECT' => 'id',
            'FROM'   => $levelticket::getTable(),
            'WHERE'  => ['tickets_id' => $ticket->fields['id']]
         ]);

         while ($data = $iterator->next()) {
            $levelticket->delete(['id' => $data['id']]);
         }
      }
   }


   function cleanDBonPurge() {
      global $DB;

      // Clean levels
      $classname = get_called_class();
      $fk        = getForeignKeyFieldForItemType($classname);
      $level     = new static::$levelclass();
      $level->deleteByCriteria([$fk => $this->getID()]);

      // Update tickets : clean SLA/OLA
      list($dateField, $laField) = static::getFieldNames($this->fields['type']);
      $iterator =  $DB->request([
         'SELECT' => 'id',
         'FROM'   => 'glpi_tickets',
         'WHERE'  => [$laField => $this->fields['id']]
      ]);

      if (count($iterator)) {
         $ticket = new Ticket();
         while ($data = $iterator->next()) {
            $ticket->deleteLevelAgreement($classname, $data['id'], $this->fields['type']);
         }
      }

      Rule::cleanForItemAction($this);
   }
}
